﻿using Microsoft.Extensions.Logging;

namespace RuoYi.Framework.Logging;

/// <summary>
///   全局日志静态类
/// </summary>
[SuppressSniffer]
public static class Log
{
  /// <summary>
  ///   手动构建方式
  /// </summary>
  /// <returns></returns>
  public static StringLoggingPart Default()
  {
    return StringLoggingPart.Default();
  }

  /// <summary>
  ///   创建日志记录器
  /// </summary>
  /// <returns></returns>
  public static ILogger CreateLogger<T>()
  {
    return App.GetRequiredService<ILogger<T>>();
  }

  /// <summary>
  ///   创建日志工厂
  /// </summary>
  /// <param name="configure">日志构建器</param>
  /// <remarks><see cref="ILoggerFactory" /> 实现了 <see cref="IDisposable" /> 接口，注意使用 `using` 控制</remarks>
  /// <returns></returns>
  public static ILoggerFactory CreateLoggerFactory(Action<ILoggingBuilder> configure = default)
  {
    return LoggerFactory.Create(builder =>
    {
      // 添加默认控制台输出
      builder.AddConsoleFormatter();

      configure?.Invoke(builder);
    });
  }

  /// <summary>
  ///   配置日志上下文
  /// </summary>
  /// <param name="properties">建议使用 ConcurrentDictionary 类型</param>
  /// <returns></returns>
  public static (ILogger logger, IDisposable scope) ScopeContext(IDictionary<object, object> properties)
  {
    return GetLogger(StringLoggingPart.Default().ScopeContext(properties));
  }

  /// <summary>
  ///   配置日志上下文
  /// </summary>
  /// <param name="configure"></param>
  /// <returns></returns>
  public static (ILogger logger, IDisposable scope) ScopeContext(Action<LogContext> configure)
  {
    return GetLogger(StringLoggingPart.Default().ScopeContext(configure));
  }

  /// <summary>
  ///   配置日志上下文
  /// </summary>
  /// <param name="context"></param>
  /// <returns></returns>
  public static (ILogger logger, IDisposable scope) ScopeContext(LogContext context)
  {
    return GetLogger(StringLoggingPart.Default().ScopeContext(context));
  }

  /// <summary>
  ///   LogInformation
  /// </summary>
  /// <param name="message"></param>
  /// <param name="args"></param>
  public static void Information(string message, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).LogInformation();
  }

  /// <summary>
  ///   LogInformation
  /// </summary>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="args"></param>
  public static void Information(string message, EventId eventId, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetEventId(eventId).LogInformation();
  }

  /// <summary>
  ///   LogInformation
  /// </summary>
  /// <param name="message"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Information(string message, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetException(exception).LogInformation();
  }

  /// <summary>
  ///   LogInformation
  /// </summary>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Information(string message, EventId eventId, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetEventId(eventId).SetException(exception).LogInformation();
  }

  /// <summary>
  ///   LogInformation
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="args"></param>
  public static void Information<TClass>(string message, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).LogInformation();
  }

  /// <summary>
  ///   LogInformation
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="args"></param>
  public static void Information<TClass>(string message, EventId eventId, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetEventId(eventId).LogInformation();
  }

  /// <summary>
  ///   LogInformation
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Information<TClass>(string message, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetException(exception).LogInformation();
  }

  /// <summary>
  ///   LogInformation
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Information<TClass>(string message, EventId eventId, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetEventId(eventId)
      .SetException(exception).LogInformation();
  }

  /// <summary>
  ///   LogWarning
  /// </summary>
  /// <param name="message"></param>
  /// <param name="args"></param>
  public static void Warning(string message, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).LogWarning();
  }

  /// <summary>
  ///   LogWarning
  /// </summary>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="args"></param>
  public static void Warning(string message, EventId eventId, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetEventId(eventId).LogWarning();
  }

  /// <summary>
  ///   LogWarning
  /// </summary>
  /// <param name="message"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Warning(string message, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetException(exception).LogWarning();
  }

  /// <summary>
  ///   LogWarning
  /// </summary>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Warning(string message, EventId eventId, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetEventId(eventId).SetException(exception).LogWarning();
  }

  /// <summary>
  ///   LogWarning
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="args"></param>
  public static void Warning<TClass>(string message, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).LogWarning();
  }

  /// <summary>
  ///   LogWarning
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="args"></param>
  public static void Warning<TClass>(string message, EventId eventId, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetEventId(eventId).LogWarning();
  }

  /// <summary>
  ///   LogWarning
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Warning<TClass>(string message, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetException(exception).LogWarning();
  }

  /// <summary>
  ///   LogWarning
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Warning<TClass>(string message, EventId eventId, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetEventId(eventId)
      .SetException(exception).LogWarning();
  }

  /// <summary>
  ///   LogError
  /// </summary>
  /// <param name="message"></param>
  /// <param name="args"></param>
  public static void Error(string message, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).LogError();
  }

  /// <summary>
  ///   LogError
  /// </summary>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="args"></param>
  public static void Error(string message, EventId eventId, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetEventId(eventId).LogError();
  }

  /// <summary>
  ///   LogError
  /// </summary>
  /// <param name="message"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Error(string message, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetException(exception).LogError();
  }

  /// <summary>
  ///   LogError
  /// </summary>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Error(string message, EventId eventId, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetEventId(eventId).SetException(exception).LogError();
  }

  /// <summary>
  ///   LogError
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="args"></param>
  public static void Error<TClass>(string message, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).LogError();
  }

  /// <summary>
  ///   LogError
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="args"></param>
  public static void Error<TClass>(string message, EventId eventId, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetEventId(eventId).LogError();
  }

  /// <summary>
  ///   LogError
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Error<TClass>(string message, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetException(exception).LogError();
  }

  /// <summary>
  ///   LogError
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Error<TClass>(string message, EventId eventId, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetEventId(eventId)
      .SetException(exception).LogError();
  }

  /// <summary>
  ///   LogDebug
  /// </summary>
  /// <param name="message"></param>
  /// <param name="args"></param>
  public static void Debug(string message, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).LogDebug();
  }

  /// <summary>
  ///   LogDebug
  /// </summary>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="args"></param>
  public static void Debug(string message, EventId eventId, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetEventId(eventId).LogDebug();
  }

  /// <summary>
  ///   LogDebug
  /// </summary>
  /// <param name="message"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Debug(string message, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetException(exception).LogDebug();
  }

  /// <summary>
  ///   LogDebug
  /// </summary>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Debug(string message, EventId eventId, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetEventId(eventId).SetException(exception).LogDebug();
  }

  /// <summary>
  ///   LogDebug
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="args"></param>
  public static void Debug<TClass>(string message, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).LogDebug();
  }

  /// <summary>
  ///   LogDebug
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="args"></param>
  public static void Debug<TClass>(string message, EventId eventId, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetEventId(eventId).LogDebug();
  }

  /// <summary>
  ///   LogDebug
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Debug<TClass>(string message, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetException(exception).LogDebug();
  }

  /// <summary>
  ///   LogDebug
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Debug<TClass>(string message, EventId eventId, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetEventId(eventId)
      .SetException(exception).LogDebug();
  }

  /// <summary>
  ///   LogTrace
  /// </summary>
  /// <param name="message"></param>
  /// <param name="args"></param>
  public static void Trace(string message, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).LogTrace();
  }

  /// <summary>
  ///   LogTrace
  /// </summary>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="args"></param>
  public static void Trace(string message, EventId eventId, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetEventId(eventId).LogTrace();
  }

  /// <summary>
  ///   LogTrace
  /// </summary>
  /// <param name="message"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Trace(string message, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetException(exception).LogTrace();
  }

  /// <summary>
  ///   LogTrace
  /// </summary>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Trace(string message, EventId eventId, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetEventId(eventId).SetException(exception).LogTrace();
  }

  /// <summary>
  ///   LogTrace
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="args"></param>
  public static void Trace<TClass>(string message, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).LogTrace();
  }

  /// <summary>
  ///   LogTrace
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="args"></param>
  public static void Trace<TClass>(string message, EventId eventId, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetEventId(eventId).LogTrace();
  }

  /// <summary>
  ///   LogTrace
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Trace<TClass>(string message, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetException(exception).LogTrace();
  }

  /// <summary>
  ///   LogTrace
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Trace<TClass>(string message, EventId eventId, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetEventId(eventId)
      .SetException(exception).LogTrace();
  }

  /// <summary>
  ///   LogCritical
  /// </summary>
  /// <param name="message"></param>
  /// <param name="args"></param>
  public static void Critical(string message, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).LogCritical();
  }

  /// <summary>
  ///   LogCritical
  /// </summary>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="args"></param>
  public static void Critical(string message, EventId eventId, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetEventId(eventId).LogCritical();
  }

  /// <summary>
  ///   LogCritical
  /// </summary>
  /// <param name="message"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Critical(string message, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetException(exception).LogCritical();
  }

  /// <summary>
  ///   LogCritical
  /// </summary>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Critical(string message, EventId eventId, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetMessage(message).SetArgs(args).SetEventId(eventId).SetException(exception).LogCritical();
  }

  /// <summary>
  ///   LogCritical
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="args"></param>
  public static void Critical<TClass>(string message, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).LogCritical();
  }

  /// <summary>
  ///   LogCritical
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="args"></param>
  public static void Critical<TClass>(string message, EventId eventId, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetEventId(eventId).LogCritical();
  }

  /// <summary>
  ///   LogCritical
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Critical<TClass>(string message, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetException(exception).LogCritical();
  }

  /// <summary>
  ///   LogCritical
  /// </summary>
  /// <typeparam name="TClass"></typeparam>
  /// <param name="message"></param>
  /// <param name="eventId"></param>
  /// <param name="exception"></param>
  /// <param name="args"></param>
  public static void Critical<TClass>(string message, EventId eventId, Exception exception, params object[] args)
  {
    StringLoggingPart.Default().SetCategory<TClass>().SetMessage(message).SetArgs(args).SetEventId(eventId)
      .SetException(exception).LogCritical();
  }

  /// <summary>
  ///   获取日志实例
  /// </summary>
  /// <param name="loggingPart"></param>
  /// <returns></returns>
  /// <exception cref="InvalidOperationException"></exception>
  private static (ILogger, IDisposable) GetLogger(StringLoggingPart loggingPart)
  {
    // 获取日志实例
    var (logger, loggerFactory, hasException) = loggingPart.GetLogger();
    var scope = logger.ScopeContext(loggingPart.LogContext);
    if (hasException)
    {
      scope?.Dispose();
      loggerFactory?.Dispose();

      throw new InvalidOperationException("Unable to set log context data.");
    }

    return (logger, scope);
  }
}
